package com.chaos.gateway.config;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.chaos.framework.model.constant.Constants;
import com.chaos.framework.model.constant.SecurityConstants;
import com.chaos.gateway.config.properties.ResourceServerProperties;
import com.chaos.gateway.helper.JwtTokenHelper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import reactor.core.publisher.Mono;

import java.net.InetSocketAddress;

/**
 * @author Jacky
 */
@Component
@Slf4j
public class ResourceServerManager implements ReactiveAuthorizationManager<AuthorizationContext> {

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    private final PathMatcher pathMatcher = new AntPathMatcher();
    @Resource
    private ResourceServerProperties resourceServerProperties;
    //    @Resource
    //    private OauthClientDetailsPermissionService oauthClientDetailsPermissionService;
    //
    //    @Resource
    //    private RbacPermissionService rbacPermissionService;
    //    @Resource
    //    private RbacUserRoleService rbacUserRoleService;
    //    @Resource
    //    private RbacRoleMenuBtnService rbacRoleMenuBtnService;
    //    @Resource
    //    private RbacPermissionMenuBtnService rbacPermissionMenuBtnService;


    private Mono<AuthorizationDecision> yesAccess() {
        return Mono.just(new AuthorizationDecision(true));
    }

    private Mono<AuthorizationDecision> noAccess() {
        return Mono.just(new AuthorizationDecision(false));
    }

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
        log.info("check authorizationContext");

        ServerHttpRequest request = authorizationContext.getExchange().getRequest();
        // 预检请求放行
        if (request.getMethod() == HttpMethod.OPTIONS) {
            return yesAccess();
        }


        String method = request.getMethod().name();
        String path = request.getURI().getPath();
        String restfulPath = method + ":" + path;

        String accessToken = request.getHeaders().getFirst(SecurityConstants.AUTHORIZATION_KEY);
        if (StringUtils.isEmpty(accessToken) || !StrUtil.startWithIgnoreCase(accessToken, SecurityConstants.JWT_PREFIX)) {
            return noAccess();
        }
        JSONObject tokenObject = JwtTokenHelper.getTokenMap(accessToken);

        // openApi
        //        if (pathMatcher.match(SecurityConstants.OPEN_API_PATTERN, path)) {
        //            return checkOpenApi(tokenObject, restfulPath);
        //        }

        // adminApi
        if (pathMatcher.match(SecurityConstants.ADMIN_API_PATTERN, path)) {
            //默认是基于权限的 api 管控
            //  return checkAdminApi(tokenObject, restfulPath);
            return yesAccess();
        }

        return checkApi(tokenObject);

    }

    //    private Mono<AuthorizationDecision> checkAdminApi(JSONObject tokenObject, String restfulPath) {
    //        String adminId = tokenObject.getStr(Constants.ADMIN_ID);
    //
    //        QueryWrapper<RbacUserRole> userRoleQuery = new QueryWrapper<>();
    //        userRoleQuery.lambda().eq(RbacUserRole::getUserId, adminId);
    //        List<RbacUserRole> userRoles = rbacUserRoleService.list(userRoleQuery);
    //        if (ObjectUtil.isEmpty(userRoles)) {
    //            return noAccess();
    //        }
    //        List<Long> roleIds = userRoles.stream().map(RbacUserRole::getRoleId).collect(Collectors.toList());
    //        if (roleIds.contains(1L)) {
    //            //超级管理员
    //            return yesAccess();
    //        }
    //        QueryWrapper<RbacPermission> queryPerm = new QueryWrapper<>();
    //        queryPerm.lambda().eq(RbacPermission::getUrlPerm, restfulPath);
    //        List<RbacPermission> perms = rbacPermissionService.list(queryPerm);
    //        if (ObjectUtil.isEmpty(perms) || perms.size() > 1) {
    //            return noAccess();
    //        }
    //        RbacPermission perm = perms.get(0);
    //        QueryWrapper<RbacPermissionMenuBtn> permMenuBtnQuery = new QueryWrapper<>();
    //        permMenuBtnQuery.lambda()
    //                .eq(RbacPermissionMenuBtn::getPermissionId, perm.getId());
    //
    //        List<RbacPermissionMenuBtn> menus = rbacPermissionMenuBtnService.list(permMenuBtnQuery);
    //
    //        Set<Long> menuIds = menus.stream().map(RbacPermissionMenuBtn::getMenuOrBtnId).collect(Collectors.toSet());
    //
    //        QueryWrapper<RbacRoleMenuBtn> roleMenuBtnQuery = new QueryWrapper<>();
    //        roleMenuBtnQuery.lambda()
    //                .in(RbacRoleMenuBtn::getMenuOrBtnId, menuIds);
    //        List<RbacRoleMenuBtn> roles = rbacRoleMenuBtnService.list(roleMenuBtnQuery);
    //
    //        Set<Long> needRoleIds = roles.stream().map(RbacRoleMenuBtn::getRoleId).collect(Collectors.toSet());
    //
    //        roleIds.retainAll(needRoleIds);
    //
    //        if (!roleIds.isEmpty()) {
    //            return yesAccess();
    //        }
    //        return noAccess();
    //
    //
    //    }

    private Mono<AuthorizationDecision> checkApi(JSONObject tokenObject) {
        Object userId = tokenObject.get(Constants.USER_ID);
        Object tenantId = tokenObject.get(Constants.TENANT_ID);
        boolean granted = ObjectUtil.isNotEmpty(userId);
        return Mono.just(new AuthorizationDecision(granted));
    }

    private Mono<AuthorizationDecision> checkOpenApi(JSONObject tokenObject, String restfulPath) {
        String clientId = tokenObject.getStr(Constants.CLIENT_ID);

        if (StringUtils.isBlank(clientId)) {
            return noAccess();
        }

        //        QueryWrapper<OauthClientDetails> query = new QueryWrapper<>();
        //        query.lambda().eq(OauthClientDetails::getClientId, clientId);
        //        List<OauthClientDetails> clients = oauthClientDetailsService.list(query);
        //        if (ObjectUtil.isEmpty(clients)) {
        //            return noAccess();
        //        }
        //
        //        QueryWrapper<RbacPermission> queryPerm = new QueryWrapper<>();
        //        queryPerm.lambda().eq(RbacPermission::getUrlPerm, restfulPath).eq(RbacPermission::getType, 2);
        //        List<RbacPermission> perms = rbacPermissionService.list(queryPerm);
        //        if (ObjectUtil.isEmpty(perms) || perms.size() > 1) {
        //            return noAccess();
        //        }
        //        RbacPermission perm = perms.get(0);
        //
        //        QueryWrapper<OauthClientDetailsPermission> queryClientPerm = new QueryWrapper<>();
        //        queryClientPerm.lambda().eq(OauthClientDetailsPermission::getPermissionId, perm.getId()).eq
        //        (OauthClientDetailsPermission::getClientId, clientId);
        //
        //        List<OauthClientDetailsPermission> clientPerms = oauthClientDetailsPermissionService.list(queryClientPerm);
        //        return !clientPerms.isEmpty() ? yesAccess() : noAccess();
        return yesAccess();
    }


}
